#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include "log.hpp"
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<unordered_map>
Log log;

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR
};

const std::string deafaultIp = "0.0.0.0";//主机任意ip接收数据
const uint16_t deafaultPort=8001;
class UDPServer
{
public:
    UDPServer(uint16_t port=deafaultPort, std::string ip = deafaultIp) : port_(port), ip_(ip)
    {
    }

    ~UDPServer()
    {
    }

    void InIt()
    {
        // 创建socket_fd(给自己弄个文件缓冲区读取数据？)
        socketfd_ = socket(AF_INET, SOCK_DGRAM, 0); // 网络协议或本地 ipv4 数据报
        if (socketfd_ < 0)
        {
            log.logmessage(Fatal, "socket creat failure,sockerfd:%d");
            exit(SOCKET_ERROR);
        }
        log.logmessage(Info, "socket creat success,socked:%d");
        // 绑定端口号
        sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET; // ipv4
        local.sin_addr.s_addr = inet_addr(ip_.c_str());
        local.sin_port=htons(port_);
        socklen_t len=sizeof(local);
        if(bind(socketfd_,(const sockaddr*)&local,len)<0)
        {
            log.logmessage(Fatal,"bind failure, error: %d error string: %s",errno,strerror(errno));
            exit(BIND_ERROR);
        }

        log.logmessage(Info,"bind success, port:%d",port_);
    }

    bool CheckUser(int ip,int port)
    {
        auto temp=clients.find(ip);
        if(temp==clients.end())
        {
            return false;
        }
        if(temp->second.sin_port!=port)
        {
            clients[ip].sin_port=port;
        }

        return true;


    }

    void Broadcast(std::string& info,sockaddr_in& client)
    {
        std::string ip=inet_ntoa(client.sin_addr);
        std::string port= std::to_string(ntohs(client.sin_port));
        for(auto items:clients)
        {
             std::string echo_string;
             echo_string.append("[");
             echo_string.append(ip);
             echo_string.append(": ");
             echo_string.append(port);
             echo_string.append("]: ");
             echo_string.append(info);
             sendto(socketfd_,echo_string.c_str(),echo_string.size(),0,(sockaddr*)&items.second,sizeof(items.second));
             
        }

        
        // sendto(socketfd_,echo_string.c_str(),echo_string.size(),0,(sockaddr*)&clinet,len);
    }
    void Run()
    {
        isRuning=true;
        char buffer[1024];
        while(isRuning)
        {
            if(isRuning==false)
            break;
            sockaddr_in clinet;
            bzero(&clinet,sizeof(clinet));
            socklen_t len=sizeof(clinet);
            int re=recvfrom(socketfd_,buffer,sizeof(buffer),0,(sockaddr*)&clinet,&len);//接收到客户端消息
            int clientIp=clinet.sin_addr.s_addr;
            if(re<0)
            {
                log.logmessage(Warning,"recvform error errno:%d strerror:%s",errno,strerror(errno));
                continue;
            }
            buffer[re]=0;
            std::string info=buffer;
            if(!CheckUser(clinet.sin_addr.s_addr,clinet.sin_port))
            {
                clients.insert({clinet.sin_addr.s_addr,clinet});
                log.logmessage(Info,"add a new user [%s：%d]", inet_ntoa(clinet.sin_addr),ntohs(clinet.sin_port));

            }
            //log.logmessage(Info,"client echo# %s",info.c_str());
            Broadcast(info,clinet);
            


        }
        
        
    }

private:
    int socketfd_;
    std::string ip_;
    uint16_t port_;
    bool isRuning;
    std::unordered_map<int,sockaddr_in> clients;
    
};